/*
 * Università degli Studi di Trento
 * Facoltà di Scienze MM.FF.NN.
 * Corso di Laurea Triennale in Informatica
 * A.A. 2010/2011
 * Progetto per il corso di Sistemi Operativi 1
 * Progetto 4: simulazione di una rotonda
 * Autori:
 *  Abram Lorenzo - 140368
 *  Dal Lago Loris - 139428
 *  Florio Alessandro - 140245
 */

/********************************************************************************
  Contiene i metodi per costruire e gestire un'automobile
********************************************************************************/

#include "car.h"

typedef struct SCar {  
  char * tag;
  int speed;
  int pos;
  long bautArrivalTime; /* tempo di arrivo alla rotatoria, relativo all'inizio del programma */
  time_t sectArrivalTime; /* momento di arrivo nel settore corrente */
  long sectStayTime;    /* permanenza nel settore corrente */
  Place startPoint;
  Place destPoint;
  Typology type;
  EventCode event;
} Car;

static void Car_init(ptrCar car, char* tag, long bautArrivalTime, Place startPoint, Place destPoint, Typology type){
  car->tag = new_vector(char, strlen(tag));
  car->tag = strcpy(car->tag, tag);
  car->pos = -1;
  car->speed = (int) type;
  car->bautArrivalTime = bautArrivalTime;
  car->sectArrivalTime = -1;
  car->sectStayTime = -1;
  car->startPoint = startPoint;
  car->destPoint = destPoint;
  car->type = type; 
  car->event = ARRIVAL;
}

ptrCar Car_create(char* tag, long bautArrivalTime, Place startPoint, Place destPoint, Typology type){
  ptrCar car = new(Car);
  Car_init(car, tag, bautArrivalTime, startPoint, destPoint, type);
  return car;
}

static int Car_nextPos(ptrCar car){
  return (car->pos+1)%Baut_LEN;
}
static int Car_prevPos(ptrCar car){
  return (car->pos+Baut_LEN-1)%Baut_LEN;
}


/* Metodo invocato per aggiornare la posizione e l'evento generato dell'auto
 * ad ogni movimento */
void Car_move (ptrCar car){
	/* Aggiorniamo i tempi di arrivo e di permanenza dell'auto */
  time_t currentTime = time(NULL);
  if (car->sectArrivalTime >= 0)
    car->sectStayTime = (long)(currentTime - car->sectArrivalTime);
  car->sectArrivalTime = currentTime;

  /* in base al tipo di movimento l'auto assumera'
   * una nuova posizione diversa */
  switch (car->event){
  case ARRIVAL: /* L'auto arriva in rotatoria */
    car->pos = 3 * car->startPoint;
    car->event = ENTER;
    break;
  case ENTER: /* L'auto inizia a girare nella rotatoria */
    car->pos = Car_nextPos(car);
    car->event = IN_SECTOR;
    break;
  case IN_SECTOR: /* L'auto continua a girare */
    if (Car_nextPos(car) != car->destPoint*3){
      car->pos = Car_nextPos(car);
      /* car->event = IN_SECTOR; */
    } else { /* se arriva il momento di uscire */
      /* car->pos = car->pos; */
      car->event = EXIT;
    }
    break;
  case EXIT: /* L'auto sta uscendo */
    car->pos = -1;
    car->event = LEAVING;
    break;
  case LEAVING: /* L'auto e' uscita e si allontana dalla rotatoria */
    throw_error("Car_move", "Non e' previsto che una auto si muova dopo aver gia' abbandonato la rotatoria!");
    break;
  default:
    throw_error("Car_move", "Evento non gestito!");
  }
}


char * Car_placeToString(Place p){
  switch (p){
  case POVO:
    return "POVO";
    break;
  case MESIANO:
    return "MESIANO";
    break;
  case VILLAZZANO:
    return "VILLAZZANO";
    break;
  case IRST:
    return "IRST";
    break;
  default:
    throw_error("Car_placeToString", "Place non gestito!");
  }
}

Place Car_stringToPlace(char * s){
  if (streq(s,"POVO")) return POVO;
  else if (streq(s, "MESIANO")) return MESIANO;
  else if (streq(s, "VILLAZZANO")) return VILLAZZANO;
  else if (streq(s, "IRST")) return IRST;
  else return ERROR_PLACE;
}

Typology Car_stringToType(char * s){
  if (streq(s, "LENTISSIMA")) return LENTISSIMA;
  else if (streq(s, "LENTA")) return LENTA;
  else if (streq(s, "VELOCE")) return VELOCE;
  else return ERROR_TYPOLOGY;
}

ptrCar Car_copy(ptrCar old_car){
	ptrCar car = new(Car);
	 car->tag = new_vector(char, strlen(old_car->tag));
	 car->tag = strcpy(car->tag, old_car->tag);
	 car->pos = old_car->pos;
	 car->speed = old_car->speed;
	 car->bautArrivalTime = old_car->bautArrivalTime;
	 car->sectArrivalTime = old_car->sectArrivalTime;
	 car->sectStayTime = old_car->sectStayTime;
	 car->startPoint = old_car->startPoint;
	 car->destPoint = old_car->destPoint;
	 car->type = old_car->type;
	 car->event = old_car->event;

	 return car;
}

/* Getty Methods */
char * Car_getTag(ptrCar car){
  return car->tag;
}
int Car_getSpeed(ptrCar car){
  return car->speed;
}
int Car_getPos(ptrCar car){
  return car->pos;
}
int Car_getPrevPos(ptrCar car){
  return Car_prevPos(car);
}
long Car_getBautArrivalTime(ptrCar car){
  return car->bautArrivalTime;
}
time_t Car_getSectArrivalTime(ptrCar car){
  return car->sectArrivalTime;
}
long Car_getSectStayTime(ptrCar car){
  return car->sectStayTime;
}
Place Car_getStartPoint(ptrCar car){
  return car->startPoint;
}
Place Car_getDestPoint(ptrCar car){
  return car->destPoint;
}
Typology Car_getType(ptrCar car){
  return car->type;
}
EventCode Car_getEvent(ptrCar car){
  return car->event;
}
char * Car_getStartPointStr(ptrCar car){
  return Car_placeToString(car->startPoint);
}
char * Car_getDestPointStr(ptrCar car){
  return Car_placeToString(car->destPoint);
}


#ifdef DEBUG
void Car_printf (ptrCar car){
  printf("AUTO %s %s %s %d %ld;\n", car->tag, Car_getStartPointStr(car), Car_getDestPointStr(car), car->type, car->bautArrivalTime);
  printf("\t\tSpeed: %d, SectArrTime: %ld, SectStayTime: %ld\n", car->speed, car->sectArrivalTime, car->sectStayTime);
}
#endif /* DEBUG */

static void Car_deinit(ptrCar car){
  /* no pointers to deinit */
};

void Car_destroy(ptrCar car){
  if (car != NULL){
    Car_deinit(car);
    delete(car);
  }
}
